home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / pp / pp-6.0 / Uip / rcvalert / dirsbr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-18  |  23.3 KB  |  1,137 lines

  1. /* imagesbr.c - image subroutines */
  2.  
  3. #ifndef    lint
  4. static char *Rcsid = "$Header: /xtel/pp/pp-beta/Uip/rcvalert/RCS/dirsbr.c,v 6.0 1991/12/18 20:39:41 jpo Rel $";
  5. #endif
  6.  
  7. /* 
  8.  * $Header: /xtel/pp/pp-beta/Uip/rcvalert/RCS/dirsbr.c,v 6.0 1991/12/18 20:39:41 jpo Rel $
  9.  *
  10.  *
  11.  * $Log: dirsbr.c,v $
  12.  * Revision 6.0  1991/12/18  20:39:41  jpo
  13.  * Release 6.0
  14.  *
  15.  * 
  16.  * 
  17.  */
  18.  
  19.  
  20. #include <ctype.h>
  21. #include <stdio.h>
  22. #include <varargs.h>
  23. #include <isode/logger.h>
  24. #include <isode/psap.h>
  25. #include <isode/quipu/bind.h>
  26. #include <isode/quipu/ds_search.h>
  27. #include <isode/quipu/entry.h>
  28. #include "image.h"
  29.  
  30. #ifndef NOPHOTOS
  31. /*  GENERAL */
  32. #if ISODE < 69
  33. #define s_filter filter
  34. #endif
  35.  
  36. static char *myname = "image";
  37. extern int debug;
  38. int errsw = OK;
  39.  
  40. static LLog _pgm_log = {
  41.     "-", NULLCP, NULLCP, LLOG_FATAL | LLOG_EXCEPTIONS | LLOG_NOTICE,
  42.     LLOG_FATAL, -1, LLOGCLS | LLOGCRT | LLOGZER | LLOGTTY, NOTOK
  43. };
  44. LLog *pgm_log = &_pgm_log;
  45. void adios ();
  46.  
  47. #define DEF_TIMELIMIT 20
  48. /*     IMAGE */
  49.  
  50.  
  51. struct image *fetch_image ();
  52.  
  53. /*     AKA */
  54.  
  55. struct aka {
  56.     struct aka *ak_forw;
  57.     struct aka *ak_back;
  58.  
  59.     time_t ak_notfound;
  60.     char   *ak_domain;
  61.     char   *ak_local;
  62.  
  63.     struct dn_seq *ak_bases;
  64.     struct image *ak_image;
  65. };
  66. static struct aka akas;
  67. static struct aka *AHead = &akas;
  68.  
  69. void init_aka ();
  70.  
  71. static int  stay_bound = 0;
  72.  
  73. DN    local_dn;
  74.  
  75.  
  76. struct dn_seq *dm2dn_seq ();
  77.  
  78.  
  79. extern char *local_dit;
  80. struct dn_seq *dn_seq_push ();
  81. int    dn_seq_print ();
  82. PE    grab_pe ();
  83.  
  84. #ifdef TESTVERSION
  85. main (argc, argv)
  86. int argc;
  87. char **argv;
  88. {
  89.     struct image *myim;
  90.  
  91.     if (argc != 3) {
  92.         fprintf (stderr, "Usdage: %s host name\n", argv[0]);
  93.         exit (1);
  94.     }
  95.  
  96.     init_aka (myname = argv[0], 1, NULLCP); 
  97.     myim = fetch_image (argv[1], argv[2]);
  98.  
  99.     if (myim) {
  100.         printf ("Retrieved photo of size %dx%d\n", myim -> width,
  101.             myim -> height);
  102.     }
  103.     else
  104.         printf ("No photo found\n");
  105.     exit (0);
  106. }
  107. #endif
  108.  
  109. /*   */
  110.  
  111. void    init_aka (pgm, stayopen, dit)
  112. char   *pgm,
  113.        *dit;
  114. int    stayopen;
  115. {
  116.     char   *cp;
  117.     register struct aka *ak;
  118.     static int once_only = 0;
  119.     static  char    *username, *password;
  120.  
  121.     if (once_only == 0) {
  122.         int    argp;
  123.         char   *arg[2],
  124.         **argptr;
  125.  
  126.         quipu_syntaxes ();
  127.  
  128.         argp = 0;
  129.         arg[argp++] = myname;
  130.         arg[argp] = NULLCP;
  131.     
  132.         dsap_init (&argp, (argptr = arg, &argptr));
  133.         quipurc (&username, &password);
  134.         once_only = 1;
  135.     }
  136.     stay_bound = stayopen;
  137.     myname = pgm;
  138.  
  139.     AHead -> ak_forw = AHead -> ak_back = AHead;
  140.     if ((ak = (struct aka *) calloc (1, sizeof *ak)) == NULL)
  141.         adios (NULLCP, "out of memory");
  142.  
  143.     ak -> ak_domain = ak -> ak_local = "";
  144.  
  145.     insque (ak, AHead -> ak_back);
  146.  
  147.     if ((local_dn = str2dn (cp = (dit ? dit
  148.                       : *local_dit != '@' ? local_dit
  149.                       : local_dit + 1)))
  150.         == NULLDN)
  151.         adios (NULLCP, "local_dit invalid: \"%s\"", cp);
  152.     do_bind (username, password);
  153. }
  154.  
  155. quipurc (username, password)
  156. char    **username, **password;
  157. {
  158.     char *home;
  159.         FILE           *file;
  160.         extern char    *local_dit;
  161.     char *p;
  162.     char Dish_Home[BUFSIZ];
  163.     char    Read_in_Stuff[BUFSIZ];
  164.     extern char *TidyString ();
  165.  
  166.     *username = *password = NULLCP;
  167.  
  168.         if (home = getenv ("QUIPURC"))
  169.         (void) strcpy (Dish_Home, home);
  170.         else if (home = getenv ("HOME"))
  171.         (void) sprintf (Dish_Home, "%s/.quipurc", home);
  172.     else
  173.         (void) strcpy (Dish_Home, "./.quipurc");
  174.  
  175.         if ((file = fopen (Dish_Home, "r")) == 0)
  176.                 return;
  177.  
  178.         while (fgets (Read_in_Stuff, sizeof Read_in_Stuff, file) != 0) {
  179.         char *part1, *part2;
  180.  
  181.                 p = SkipSpace (Read_in_Stuff);
  182.                 if (( *p == '#') || (*p == '\0'))
  183.                         continue; /* ignore comments and blanks */
  184.  
  185.                 part1 = p;
  186.                 if ((part2 = index (p,':')) == NULLCP)
  187.             continue;
  188.  
  189.                 *part2++ = '\0';
  190.                 part2 = TidyString (part2);
  191.  
  192.                 if (lexequ (part1, "username") == 0)
  193.                         *username = strdup(*part2 != '@' ? part2 : part2 + 1);
  194.  
  195.                 else if (lexequ (part1, "password") == 0) {
  196.             *password = strdup(part2);
  197.                 } else if (lexequ (part1, "dsap") == 0)
  198.                         (void) tai_string (part2);
  199.                 else if (lexequ (part1, "isode") == 0) {
  200.                         char * split;
  201.                         if ((split = index (part2,' ')) != NULLCP) {
  202.                                 *split++ = 0;
  203.                                 (void)isodesetvar (part2,strdup(split),0);
  204.                         }
  205.         }
  206.         }
  207.         (void) fclose (file);
  208.  
  209. }
  210. /*   */
  211.  
  212. static struct aka *mbox2ak (local, domain)
  213. char   *local,
  214.        *domain;
  215. {
  216.     register struct aka *ak, *am, *adm= NULL;
  217.  
  218.     if (domain == NULL)
  219.         domain = "";
  220.     if (local == NULL)
  221.         local = "";
  222.  
  223.     for (ak = AHead -> ak_forw; ak != AHead; ak = ak -> ak_forw) {
  224.         if (lexequ (domain, ak -> ak_domain) != 0)
  225.             continue;
  226.         adm = ak;
  227.         if (lexequ (local, ak -> ak_local) == 0) {
  228.             if (debug)
  229.                 LLOG (pgm_log, LLOG_NOTICE,
  230.                       ("hit \"%s\" \"%s\"", domain, local));
  231.  
  232.             return ak;
  233.         }
  234.     }
  235.     if (adm) {
  236.         if (debug)
  237.             LLOG (pgm_log, LLOG_NOTICE,
  238.                   ("partial hit \"%s\"", domain));
  239.         if ((am = (struct aka *) calloc (1, sizeof *am)) == NULL
  240.             || (am -> ak_domain = strdup (domain)) == NULL
  241.             || (am -> ak_local = strdup (local)) == NULL)
  242.             adios (NULLCP, "out of memory");
  243.         am -> ak_bases = adm -> ak_bases;
  244.         insque (ak = am, AHead);
  245.  
  246.         return ak;
  247.     }
  248.     
  249.     if ((am = (struct aka *) calloc (1, sizeof *am)) == NULL
  250.         || (am -> ak_domain = strdup (domain)) == NULL
  251.         || (am -> ak_local = strdup (local)) == NULL)
  252.         adios (NULLCP, "out of memory");
  253.  
  254.     if (debug)
  255.         LLOG (pgm_log, LLOG_NOTICE,
  256.               ("miss \"%s\" \"%s\"", domain, local));
  257.  
  258.     if (index (domain, '.'))
  259.         am -> ak_bases = dm2dn_seq (domain);
  260.     else
  261.         am -> ak_bases = dn_seq_push (local_dn, NULLDNSEQ);
  262.  
  263.     insque (ak = am, AHead);
  264.  
  265.     return ak;
  266. }
  267.  
  268. /*     DIRECTORY */
  269.  
  270. #define    ADOMAIN        "associatedDomain"
  271. #define    PHOTO        "photo"
  272. #define    USERID        "userid"
  273. #define MAILBOX        "rfc822Mailbox"
  274. #define OTHERMAILBOX    "otherMailbox"
  275. #define COMMONNAME     "commonname"
  276. #define SURNAME        "surname"
  277.  
  278. static int bound = 0;
  279. static int dlevel = 0;
  280. static AttributeType adomain_t;
  281.  
  282. struct dn_seq *dm2dn_seq_aux ();
  283.  
  284.  
  285. static struct dn_seq *dm2dn_seq (dm)
  286. char   *dm;
  287. {
  288.     register char *dp;
  289.     char *av[100];
  290.     int count;
  291.  
  292.     for (dp = dm, av[count = 0] = dm; *dp; dp++) {
  293.         if (isupper (*dp))
  294.             *dp = tolower (*dp);
  295.         if (*dp == '.')
  296.             av[++count] = dp+1;
  297.     }
  298.     av[++count] = NULL;
  299.  
  300.     if ((adomain_t = AttrT_new (ADOMAIN)) == NULL)
  301.         adios ("invalid attribute type \"%s\"", ADOMAIN);
  302.  
  303.     dlevel = 0;
  304.  
  305.     if (!bound && do_bind (NULLCP, NULLCP) == NOTOK)
  306.         return NULLDNSEQ;
  307.  
  308.     return dm2dn_seq_aux (dm, count, 0, av, NULLDN, NULLDNSEQ);
  309. }
  310.  
  311. /*   */
  312.  
  313. static int find_best_match (atv, maxdmn, av)
  314. AV_Sequence atv;
  315. int maxdmn;
  316. char *av[];
  317. {
  318.     int best = maxdmn + 1;
  319.     int i;
  320.     char buffer[BUFSIZ];
  321.     PS    ps;
  322.  
  323.     if ((ps = ps_alloc (str_open)) == NULLPS
  324.         || str_setup (ps, buffer, sizeof buffer, 1) == NOTOK)
  325.         adios ("can't set up PS stream");
  326.  
  327.     for (; atv; atv = atv -> avseq_next) {
  328.         AttrV_print (ps, &atv -> avseq_av, EDBOUT);
  329.         *ps->ps_ptr = NULL;
  330.         for (i = 0; i < maxdmn; i++)
  331.             if (lexequ (buffer, av[i]) == 0)
  332.                 if (i < best) {
  333.                     best = i;
  334.                     break;
  335.                 }
  336.         if (str_setup (ps, buffer, sizeof buffer, 1) == NOTOK)
  337.             adios ("can't reset PS stream");
  338.     }
  339.     ps_free (ps);
  340.     if (best > maxdmn)
  341.         return best;
  342.     return maxdmn - best;
  343. }
  344.  
  345. static struct dn_seq *dm2dn_seq_aux (dm, maxdmn, ndmn, av, dn, dlist)
  346. char   *dm;
  347. DN    dn;
  348. int maxdmn, ndmn;
  349. char *av[];
  350. struct dn_seq *dlist;
  351. {
  352.     char   buffer[BUFSIZ];
  353.     struct ds_search_arg search_arg;
  354.     register struct ds_search_arg *sa = &search_arg;
  355.     struct ds_search_result search_result;
  356.     register CommonArgs *ca;
  357.     register struct ds_search_result *sr = &search_result;
  358.     struct DSError error;
  359.     register struct DSError *se = &error;
  360.     PS        ps;
  361.  
  362.     if ((ps = ps_alloc (str_open))
  363.         && str_setup (ps, buffer, sizeof buffer, 1) != NOTOK) {
  364.         dn_print (ps, dn, EDBOUT);
  365.         ps_print (ps, " ");
  366.         *--ps -> ps_ptr = NULL, ps -> ps_cnt ++;
  367.     }
  368.     else
  369.         buffer[0] = NULL;
  370.     if (ps)
  371.         (void) ps_free (ps);
  372.  
  373.     if (debug)
  374.         fprintf (stderr, "dlevel=%d maxlevel=%d dm=%s dn=%s\n",
  375.              ndmn, maxdmn, dm, buffer);
  376.  
  377.     bzero ((char *) sa, sizeof *sa);
  378.  
  379.     ca = &sa -> sra_common;
  380.     ca -> ca_servicecontrol.svc_options = SVC_OPT_PREFERCHAIN;
  381.     ca -> ca_servicecontrol.svc_timelimit = DEF_TIMELIMIT;
  382.     ca -> ca_servicecontrol.svc_sizelimit = SVC_NOSIZELIMIT;
  383.  
  384.     sa -> sra_baseobject = dn;
  385.     sa -> sra_subset = SRA_ONELEVEL;
  386.     sa -> sra_searchaliases = FALSE;
  387.  
  388.     sa -> sra_eis.eis_allattributes = FALSE;
  389.     sa -> sra_eis.eis_select = as_comp_new (str2AttrT (ADOMAIN), NULLAV,
  390.                         NULLACL_INFO);
  391.     sa -> sra_eis.eis_infotypes = EIS_ATTRIBUTESANDVALUES;
  392.  
  393.     for (;;) {
  394.         int        i;
  395.         EntryInfo  *ptr;
  396.         register s_filter *fi;
  397.  
  398.         if (debug)
  399.             fprintf (stderr,
  400.                  "-- dlevel=%d maxlevel=%d, domain=%s dn=%s\n",
  401.                  ndmn, maxdmn, dm, buffer);
  402.  
  403.         if (ndmn >= maxdmn)
  404.             break;
  405.  
  406.         sa -> sra_filter = fi = filter_alloc ();
  407.  
  408.         bzero ((char *) fi, sizeof *fi);
  409.         fi -> flt_type = FILTER_OR;
  410.  
  411.         for (i = 0; i < maxdmn - ndmn; i++) {
  412.             s_filter *f;
  413.  
  414.             f = filter_alloc ();
  415.             bzero ((char *)f, sizeof *f);
  416.             f -> flt_type = FILTER_ITEM;
  417.             f -> FUITEM.fi_type = FILTERITEM_EQUALITY;
  418.             f -> FUITEM.UNAVA.ava_type = AttrT_cpy(adomain_t);
  419.             f -> FUITEM.UNAVA.ava_value =
  420.                 str2AttrV (av[i], adomain_t -> oa_syntax);
  421.  
  422.             f -> flt_next = fi -> FUFILT;
  423.             fi -> FUFILT = f;
  424.         }
  425.  
  426.         if (ds_search (sa, se, sr) != DS_OK) {
  427.             if (debug)
  428.                 LLOG (pgm_log, LLOG_EXCEPTIONS,
  429.                       ("search operation failed (%d)",
  430.                        se -> dse_type));
  431.  
  432.             if (se -> dse_type == DSE_REMOTEERROR) {
  433.                 (void) ds_unbind ();
  434.                 bound = 0;
  435.             }
  436.  
  437.             goto free_filter;
  438.         }
  439.  
  440.         if (sr -> srr_correlated != TRUE)
  441.             correlate_search_results (sr);
  442.  
  443.         if (sr -> CSR_entries == NULLENTRYINFO) {
  444.             if (debug)
  445.                 LLOG (pgm_log, LLOG_NOTICE,
  446.                       ("search for %s \"%s\" at baseobject \"%s\" failed",
  447.                        ADOMAIN, dm, buffer));
  448.             goto free_filter;
  449.         }
  450.  
  451.         if (debug)
  452.             LLOG (pgm_log, LLOG_NOTICE,
  453.                   ("search for %s \"%s\" at baseobject \"%s\" succeeded",
  454.                    ADOMAIN, dm, buffer));
  455.  
  456.         for (ptr = sr -> CSR_entries; ptr; ptr = ptr -> ent_next) {
  457.             struct dn_seq *dprev = dlist;
  458.             Attr_Sequence as;
  459.             int best = maxdmn + 1;
  460.  
  461.             for (as = ptr -> ent_attr; as; as = as -> attr_link) {
  462.                 if (AttrT_cmp (as -> attr_type,
  463.                            adomain_t) == 0) {
  464.                     i = find_best_match (as -> attr_value,
  465.                                  maxdmn, av);
  466.                     if (i < best)
  467.                         best = i;
  468.                 }
  469.             }
  470.             if (best < maxdmn) /* ok match */
  471.                 ndmn = best;
  472.             else if (best == maxdmn) { /* perfect match */
  473.                 dlist = dn_seq_push (ptr -> ent_dn, dlist);
  474.                 continue;
  475.             }
  476.             else
  477.                 continue;
  478.  
  479.             dlist = dm2dn_seq_aux (dm, maxdmn, ndmn, av,
  480.                            ptr -> ent_dn, dlist);
  481.  
  482.             if (dprev == dlist) /* nothing better in recursion? */
  483.                 dlist = dn_seq_push (ptr -> ent_dn, dlist);
  484.         }
  485.  
  486.         dn_free (sr -> CSR_object);
  487.         entryinfo_free (sr -> CSR_entries, 0);
  488.         crefs_free (sr -> CSR_cr);
  489.         free_filter: ;
  490.         filter_free (sa -> sra_filter);
  491.         break;
  492.     }
  493.  
  494.     return dlist;
  495. }
  496.  
  497. /*   */
  498. typedef struct SearchKeys {
  499.     char    *type;
  500.     char    *value;
  501. } SearchKeys;
  502.  
  503. static  int image_search (ak, imp)
  504. register struct aka *ak;
  505. struct image *imp;
  506. {
  507.     register struct dn_seq *dlist;
  508.     SearchKeys sk[10];
  509.     int    retval;
  510.     char buf[BUFSIZ];
  511.     char    *cp;
  512.     int n;
  513.  
  514.     if (debug) {
  515.         LLOG (pgm_log, LLOG_NOTICE, ("searching for %s %s",
  516.                          ak -> ak_domain, ak -> ak_local));
  517.         pslog (pgm_log, LLOG_NOTICE, "  using baseobjects ",
  518.                dn_seq_print, (caddr_t) ak -> ak_bases);
  519.     }
  520.  
  521.     sk[0].type = MAILBOX;
  522.     (void) sprintf (buf, "%s@%s", ak -> ak_local, ak -> ak_domain);
  523.     sk[0].value = strdup(buf);
  524.     sk[1].type = USERID;
  525.     sk[1].value = strdup(ak -> ak_local);
  526.     sk[2].type = OTHERMAILBOX;
  527.     (void) sprintf (buf, "internet$%s@%s",
  528.             ak -> ak_local, ak -> ak_domain);
  529.     sk[2].value = strdup(buf);
  530.     sk[3].type = sk[3].value = NULLCP;
  531.  
  532.     retval = NOTOK;
  533.     for (dlist = ak -> ak_bases; dlist; dlist = dlist -> dns_next) {
  534.         if ((retval = do_search (dlist -> dns_dn,
  535.                      sk, imp)) != DONE)
  536.             break;
  537.     }
  538.     for (n = 0; sk[n].type; n++)
  539.         free (sk[n].value);
  540.  
  541.     if (retval != DONE)
  542.         return retval;
  543.  
  544.     /* OK - try some more heuristics */
  545.     n = 0;
  546.     sk[n].type = COMMONNAME;
  547.     sk[n++].value = strdup(ak -> ak_local);
  548.  
  549.     if ((cp = rindex(ak -> ak_local, '.')) != NULL) {
  550.         (void) strcpy (buf, ak -> ak_local); /* try replacing '.'->' ' */
  551.         for (cp = buf; *cp; cp++)
  552.             if (*cp == '.')
  553.                 *cp = ' ';
  554.         sk[n].type = COMMONNAME;
  555.         sk[n++].value = strdup(buf);
  556.     }
  557.     sk[n].type = sk[n].value = NULLCP;
  558.  
  559.     retval = NOTOK;
  560.  
  561.     for (dlist = ak -> ak_bases; dlist; dlist = dlist -> dns_next) {
  562.         if ((retval = do_search (dlist -> dns_dn,
  563.                      sk, imp)) != DONE)
  564.             break;
  565.     }
  566.     if (retval != DONE)
  567.         return retval;
  568.  
  569.     n = 0;
  570.     sk[n].type = SURNAME;
  571.     sk[n++].value = strdup(ak -> ak_local);
  572.     if ((cp = rindex(ak -> ak_local, '.')) != NULL) {
  573.         sk[n].type = SURNAME; /* try last component as surname */
  574.         sk[n++].value = cp + 1;
  575.     }
  576.     sk[n].type = sk[n].value = NULLCP;
  577.  
  578.     retval = NOTOK;
  579.  
  580.     for (dlist = ak -> ak_bases; dlist; dlist = dlist -> dns_next) {
  581.         if ((retval = do_search (dlist -> dns_dn,
  582.                      sk, imp)) != DONE)
  583.             break;
  584.     }
  585.     return retval;
  586. }
  587.  
  588. static AttributeType t_photo, t_phone, t_address, t_description, t_info;
  589.  
  590. struct pairs {
  591.     char *p_name;
  592.     AttributeType *p_at;
  593. } pairs[] = {
  594.     PHOTO,            &t_photo,
  595.     "telephoneNumber",    &t_phone,
  596.     "postalAddress",    &t_address,
  597.     "description",        &t_description,
  598.     "info",            &t_info,
  599.     NULL,
  600. };
  601.  
  602. static char *as2str (as)
  603. Attr_Sequence as;
  604. {
  605.     static PS ps;
  606.     char buffer[BUFSIZ];
  607.  
  608.     if (ps == NULLPS) {
  609.         if ((ps = ps_alloc (str_open)) == NULLPS)
  610.             adios (NULLCP, "Out of memory");
  611.     }
  612.     if (str_setup (ps, buffer, sizeof buffer, 1) == NOTOK)
  613.         adios (NULLCP, "Can't setup PS");
  614.  
  615.     avs_print (ps, as -> attr_value, READOUT);
  616.     ps_print (ps, " ");
  617.     *--ps -> ps_ptr = NULL, ps -> ps_cnt ++;
  618.  
  619.     return strdup (buffer);
  620. }
  621.  
  622. static Attr_Sequence get_select ()
  623. {
  624.     static Attr_Sequence as = NULL;
  625.  
  626.     if (!as) {
  627.         struct pairs *p;
  628.         AttributeType at;
  629.  
  630.         for (p = pairs; p -> p_name; p++) {
  631.             at = *p -> p_at = AttrT_new (p -> p_name);
  632.  
  633.             if (at)
  634.                 as = as_merge (as,
  635.                            as_comp_new (AttrT_cpy(at),
  636.                                 NULLAV,
  637.                                 NULLACL_INFO));
  638.         }
  639.     }
  640.  
  641.     return as;
  642. }
  643.  
  644. decode_result (imp, eptr)
  645. struct image *imp;
  646. Attr_Sequence eptr;
  647. {
  648.  
  649.     for (; eptr; eptr = eptr -> attr_link) {
  650.         if (AttrT_cmp (eptr -> attr_type, t_photo) == 0)
  651.             imp -> pe =
  652.                 pe_cpy (grab_pe (eptr -> attr_value
  653.                          -> avseq_av));
  654.         else if (AttrT_cmp (eptr -> attr_type, t_info) == 0)
  655.             imp -> info = as2str (eptr);
  656.         else if (AttrT_cmp (eptr -> attr_type, t_description) == 0)
  657.             imp -> description = as2str (eptr);
  658.         else if (AttrT_cmp (eptr -> attr_type, t_address) == 0)
  659.             imp -> address = as2str (eptr);
  660.         else if (AttrT_cmp (eptr -> attr_type, t_phone) == 0)
  661.             imp -> phone = as2str (eptr);
  662.     }
  663. }
  664.  
  665. static int do_search (dn, sk, imp)
  666. DN    dn;
  667. SearchKeys sk[];
  668. struct image *imp;
  669. {
  670.     struct ds_search_arg search_arg;
  671.     register struct ds_search_arg *sa = &search_arg;
  672.     struct ds_search_result search_result;
  673.     register CommonArgs *ca;
  674.     register struct ds_search_result *sr = &search_result;
  675.     struct DSError error;
  676.     register struct DSError *se = &error;
  677.     extern int dn_print();
  678.     extern char *dn2ufn ();
  679.     SearchKeys *skp;
  680.     s_filter *fi;
  681.  
  682.     bzero ((char *) sa, sizeof *sa);
  683.  
  684.     ca = &sa -> sra_common;
  685.     ca -> ca_servicecontrol.svc_options = SVC_OPT_PREFERCHAIN;
  686.     ca -> ca_servicecontrol.svc_timelimit = DEF_TIMELIMIT;
  687.     ca -> ca_servicecontrol.svc_sizelimit = 1;
  688.  
  689.     sa -> sra_subset = SRA_WHOLESUBTREE;
  690.     sa -> sra_searchaliases = TRUE;
  691.  
  692.     if ((sa -> sra_baseobject = dn) == NULL)
  693.         return DONE;
  694.  
  695.     sa -> sra_filter = fi = filter_alloc ();
  696.  
  697.     bzero ((char *) fi, sizeof *fi);
  698.     fi -> flt_type = FILTER_OR;
  699.  
  700.     for (skp = sk; skp -> type; skp ++) {
  701.         s_filter *f;
  702.         AttributeType at;
  703.  
  704.         f = filter_alloc ();
  705.         bzero ((char *) f, sizeof *f);
  706.  
  707.         f -> flt_type = FILTER_ITEM;
  708.         f -> FUITEM.fi_type = FILTERITEM_EQUALITY;
  709.         if ((f -> FUITEM.UNAVA.ava_type = at =
  710.              AttrT_new (skp -> type)) == NULL)
  711.             adios ("invalid attribute type \"%s\"", USERID);
  712.         f -> FUITEM.UNAVA.ava_value =
  713.             str2AttrV (skp -> value, at -> oa_syntax);
  714.         f -> flt_next = fi -> FUFILT;
  715.         fi -> FUFILT = f;
  716.     }
  717.  
  718.     sa -> sra_eis.eis_allattributes = FALSE;
  719.     sa -> sra_eis.eis_select = get_select ();
  720.     sa -> sra_eis.eis_infotypes = EIS_ATTRIBUTESANDVALUES;
  721.  
  722.     if (debug) {
  723.         extern int fi_print ();
  724.  
  725.         pslog (pgm_log, LLOG_NOTICE, "Searching for ",
  726.                fi_print, (caddr_t)fi);
  727.         pslog (pgm_log, LLOG_NOTICE, " from  ",
  728.                dn_print, (caddr_t) dn);
  729.     }
  730.     if (ds_search (sa, se, sr) != DS_OK) {
  731.         if (debug)
  732.             LLOG (pgm_log, LLOG_EXCEPTIONS,
  733.                   ("search operation failed (%d)",
  734.                    se -> dse_type));
  735.  
  736.         switch (se -> dse_type) {
  737.             case DSE_REMOTEERROR:
  738.             (void) ds_unbind ();
  739.             bound = 0;
  740.             break;
  741.             default:
  742.             break;
  743.         }
  744.  
  745.         filter_free (sa -> sra_filter);
  746.         return bound == 0 ? NOTOK : DONE;
  747.     }
  748.  
  749.     if (sr -> srr_correlated != TRUE)
  750.         correlate_search_results (sr);
  751.  
  752.     switch (sr -> CSR_limitproblem) {
  753.         case LSR_NOLIMITPROBLEM:
  754.         break;
  755.         case LSR_TIMELIMITEXCEEDED:
  756.         if (debug)
  757.             LLOG (pgm_log, LLOG_NOTICE,
  758.                   ("took tooo long"));
  759.         /* fall */
  760.         case LSR_ADMINSIZEEXCEEDED:
  761.         filter_free (sa -> sra_filter);
  762.         return NOTOK;
  763.  
  764.         case LSR_SIZELIMITEXCEEDED:
  765.         if (debug)
  766.             pslog (pgm_log, LLOG_NOTICE,
  767.                    "search: hit too many targets at ",
  768.                    dn_print, (caddr_t)dn);
  769.         break; /* carry on anyway */
  770.     }
  771.         
  772.     if (sr -> CSR_entries == NULLENTRYINFO) {
  773.         if (debug)
  774.             pslog (pgm_log, LLOG_NOTICE,
  775.                    "search failed at baseobject ",
  776.                    dn_print, (caddr_t) dn);
  777.         filter_free (sa -> sra_filter);
  778.         return DONE;
  779.     }
  780.  
  781.     if (sr -> CSR_entries -> ent_attr == NULLATTR) {
  782.         if (debug)
  783.             pslog (pgm_log, LLOG_NOTICE,
  784.                    "search succeeded (but no attribute) at ",
  785.                    dn_print, (caddr_t) dn);
  786.     }
  787.     else {
  788.         if (debug)
  789.             pslog (pgm_log, LLOG_NOTICE,
  790.                    "search succeeded at ",
  791.                    dn_print, (caddr_t) dn);
  792.         decode_result (imp, sr -> CSR_entries -> ent_attr);
  793.     }
  794.  
  795.     imp -> ufnname = dn2ufn (sr ->CSR_entries -> ent_dn, -1);
  796.  
  797.     dn_free (sr -> CSR_object);
  798.     entryinfo_free (sr -> CSR_entries, 0);
  799.     crefs_free (sr -> CSR_cr);
  800.     filter_free (sa -> sra_filter);
  801.     return OK;
  802.  
  803. }
  804. /*   */
  805.  
  806. static int do_bind (dn, passwd)
  807. char    *dn;
  808. char *passwd;
  809. {
  810.     struct ds_bind_arg bind_arg,
  811.                bind_result;
  812.     register struct ds_bind_arg *ba = &bind_arg,
  813.                 *br = &bind_result;
  814.     struct ds_bind_error bind_error;
  815.     register struct ds_bind_error *be = &bind_error;
  816.     static char *savedn, *savepasswd;
  817.  
  818.     bzero ((char *) ba, sizeof *ba);
  819.     ba -> dba_version = DBA_VERSION_V1988;
  820.     ba -> dba_auth_type = DBA_AUTH_NONE;
  821.     if (dn || (dn = savedn) != NULLCP) {
  822.         if (savedn == NULLCP)
  823.             savedn = strdup (dn);
  824.         ba -> dba_dn = str2dn (dn);
  825.         if (passwd || (passwd=savepasswd) != NULLCP) {
  826.             if (savepasswd == NULLCP)
  827.                 savepasswd = strdup (passwd);
  828.             (void) strcpy (ba -> dba_passwd, passwd);
  829.             ba -> dba_auth_type = DBA_AUTH_SIMPLE;
  830.         }
  831.     }
  832.             
  833.  
  834.     if (ds_bind (ba, be, br) != DS_OK) {
  835.     if (debug)
  836.         LLOG (pgm_log, LLOG_EXCEPTIONS,
  837.           ("directory bind failed: %s",
  838.            be -> dbe_type == DBE_TYPE_SECURITY ? "security error"
  839.                                : "DSA unavailable"));
  840.  
  841.     return NOTOK;
  842.     }
  843.  
  844.     bound = 1;
  845.  
  846.     return OK;
  847. }
  848.  
  849. /*     IMAGE */
  850.  
  851. static int    passno;
  852. static int    x, y, maxx;
  853.  
  854. static struct image *the_image = NULL;
  855.  
  856. /*   */
  857. void image_free (imp)
  858. struct image *imp;
  859. {
  860.     if (imp -> data)    qb_free(imp ->data);
  861.     if (imp -> ufnname)    free (imp->ufnname);
  862.     if (imp -> phone)    free (imp -> phone);
  863.     if (imp -> description)    free (imp -> description);
  864.     if (imp -> info)    free (imp -> info);
  865.     if (imp -> address)    free (imp -> address);
  866.     if (imp -> pe)        pe_free (imp->pe);
  867.     free ((char *)imp);
  868. }
  869.  
  870. struct image *fetch_image (local, domain)
  871. char   *local,
  872.        *domain;
  873. {
  874.     register struct aka *ak;
  875.     time_t now;
  876.  
  877.     (void) time(&now);
  878.  
  879.     if ((ak = mbox2ak (local, domain)) == NULL)
  880.         return NULL;
  881.  
  882.     if (ak -> ak_image)
  883.         return ak -> ak_image;
  884.     if (ak -> ak_notfound > now - 30*60) {
  885.         if (debug)
  886.             LLOG (pgm_log, LLOG_NOTICE, ("Hit negative cache!"));
  887.         return NULL; /* neg cache */
  888.     }
  889.     if (!bound && do_bind (NULLCP, NULLCP) == NOTOK)
  890.         return NULL;
  891.  
  892.     if ((the_image = (struct image *) calloc (1, sizeof *the_image)) == NULL) {
  893.         if (debug)
  894.             fprintf (stderr, "calloc fails");
  895.         return NULL;
  896.     }
  897.     if (image_search (ak, the_image) == NOTOK) {
  898.         ak -> ak_notfound = now;
  899.         return NULL;
  900.     }
  901.  
  902.     if (!stay_bound) {
  903.         (void) ds_unbind ();
  904.         bound = 0;
  905.     }
  906.  
  907.     if (the_image -> pe)
  908.         dec_photo (the_image);
  909.     return (ak -> ak_image = the_image);
  910. }
  911.  
  912.  
  913. dec_photo (imp)
  914. struct image *imp;
  915. {
  916.     PS ps;
  917.     PE pe = imp -> pe;
  918.  
  919.     imp -> pe = NULLPE;
  920.  
  921.     if ((ps = ps_alloc (str_open)) == NULLPS) {
  922.         if (debug)
  923.             fprintf (stderr, "ps_alloc: failed\n");
  924.  
  925.         goto out;
  926.     }
  927.     if (str_setup (ps, NULLCP, 0, 0) == NOTOK) {
  928.         if (debug)
  929.             fprintf (stderr, "ps_alloc: %s\n",
  930.                  ps_error (ps -> ps_errno));
  931.  
  932.         goto out;
  933.     }
  934.     
  935.     if (pe2ps (ps, pe) == NOTOK) {
  936.         if (debug)
  937.             fprintf (stderr, "pe2ps: %s\n",
  938.                  pe_error (pe -> pe_errno));
  939.  
  940.         goto out;
  941.     }
  942.  
  943.     for (passno = 1; passno < 3; passno++)
  944.         if (decode_t4 (ps -> ps_base, PHOTO,
  945.                    ps -> ps_ptr - ps -> ps_base)
  946.             == NOTOK) {
  947.             fprintf (stderr, "\n");
  948.             if (imp -> data) {
  949.                 qb_free (imp -> data);
  950.                 imp -> data = NULL;
  951.             }
  952.             break;
  953.         }
  954.  
  955.     out: ;
  956.     if (ps)
  957.         ps_free (ps);
  958.     pe_free (pe);
  959. }
  960. /*   */
  961.  
  962. /* ARGSUSED */
  963.  
  964. photo_start (name)
  965. char   *name;
  966. {
  967.     if (passno == 1)
  968.     maxx = 0;
  969.     x = y = 0;
  970.  
  971.     return OK;
  972. }
  973.  
  974.  
  975. /* ARGSUSED */
  976.  
  977. photo_end (name)
  978. char   *name;
  979. {
  980.     int        len;
  981.     register struct qbuf *qb,
  982.     *pb;
  983.     
  984.     if (passno == 1) {
  985.         x = maxx, y--;
  986.  
  987.         if (debug)
  988.             fprintf (stderr, "ending pass one for \"%s\", %dx%d\n",
  989.                  name, x, y);
  990.  
  991.         the_image -> width = x, the_image -> height = y;
  992.  
  993.         len = ((the_image -> width + 7) / 8) * the_image -> height;
  994.         if ((the_image -> data = qb = (struct qbuf *) malloc (sizeof *qb)) == NULL) {
  995.             if (debug)
  996.                 fprintf (stderr, "unable to allocate qbuf");
  997.             return NOTOK;
  998.         }
  999.         qb -> qb_forw = qb -> qb_back = qb;
  1000.         qb -> qb_data = NULL, qb -> qb_len = len;
  1001.     
  1002.         if ((pb = (struct qbuf *) calloc ((unsigned) (sizeof *pb + len), 1))
  1003.             == NULL) {
  1004.             if (debug)
  1005.                 fprintf (stderr, "unable to allocate qbuf (%d+%d)",
  1006.                      sizeof *qb, len);
  1007.             return NOTOK;
  1008.         }
  1009.         pb -> qb_data = pb -> qb_base, pb -> qb_len = len;
  1010.         insque (pb, qb);
  1011.         return OK;
  1012.     }
  1013.     return OK;
  1014. }
  1015.  
  1016.  
  1017. photo_black (length)
  1018. int    length;
  1019. {
  1020.     if (passno == 2) {
  1021.     register int    i,
  1022.             j;
  1023.     register unsigned char *cp;
  1024.  
  1025.     cp = (unsigned char *) the_image -> data -> qb_forw -> qb_data
  1026.                        + ((the_image -> width + 7) / 8) * y + x / 8;
  1027.     i = x % 8;
  1028.     for (j = length; j > 0; j--) {
  1029.         *cp |= 1 << i;
  1030.         if (++i == 8)
  1031.         cp++, i = 0;
  1032.     }
  1033.  
  1034.     }
  1035.  
  1036.     x += length;
  1037.  
  1038.     return OK;
  1039. }
  1040.  
  1041.  
  1042. photo_white (length)
  1043. int    length;
  1044. {
  1045.     x += length;
  1046.  
  1047.     return OK;
  1048. }
  1049.  
  1050.  
  1051. /* ARGSUSED */
  1052.  
  1053. photo_line_end (line)
  1054. caddr_t line;
  1055. {
  1056.     if (passno == 1 && x > maxx)
  1057.     maxx = x;
  1058.     x = 0, y++;
  1059.  
  1060.     return OK;
  1061. }
  1062.  
  1063. /*     ERRORS */
  1064.  
  1065. #ifndef    lint
  1066. void    _advise ();
  1067.  
  1068.  
  1069. void    adios (va_alist)
  1070. va_dcl
  1071. {
  1072.     va_list ap;
  1073.  
  1074.     va_start (ap);
  1075.  
  1076.     _advise (ap);
  1077.  
  1078.     va_end (ap);
  1079.  
  1080.     _exit (1);
  1081. }
  1082. #else
  1083. /* VARARGS */
  1084.  
  1085. void    adios (what, fmt)
  1086. char   *what,
  1087.        *fmt;
  1088. {
  1089.     adios (what, fmt);
  1090. }
  1091. #endif
  1092.  
  1093.  
  1094. #ifndef    lint
  1095. void    advise (va_alist)
  1096. va_dcl
  1097. {
  1098.     va_list ap;
  1099.  
  1100.     va_start (ap);
  1101.  
  1102.     _advise (ap);
  1103.  
  1104.     va_end (ap);
  1105. }
  1106.  
  1107.  
  1108. static void  _advise (ap)
  1109. va_list    ap;
  1110. {
  1111.     char    buffer[BUFSIZ];
  1112.  
  1113.     asprintf (buffer, ap);
  1114.  
  1115.     (void) fflush (stdout);
  1116.  
  1117.     if (errsw != NOTOK) {
  1118.     fprintf (stderr, "%s: ", myname);
  1119.     (void) fputs (buffer, stderr);
  1120.     (void) fputc ('\n', stderr);
  1121.  
  1122.     (void) fflush (stderr);
  1123.     }    
  1124. }
  1125. #else
  1126. /* VARARGS */
  1127.  
  1128. void    advise (what, fmt)
  1129. char   *what,
  1130.        *fmt;
  1131. {
  1132.     advise (what, fmt);
  1133. }
  1134. #endif
  1135.  
  1136. #endif
  1137.